package bin;

import java.security.*;


public class PasswordCreator {
	public static final int SET_UPPER = 0x1;
	public static final int SET_LOWER = 0x10;
	public static final int SET_NUMBER= 0x100;
	public static final int SET_SPECIAL=0x1000;
	private static final int MAXLEN = 50;
	private String password;
	public PasswordCreator() {}
	
	public PasswordCreator(String url, String input, int len, int mod) 
	throws NoSuchAlgorithmException {
			password = createPassword(url, input, len, mod);
	}
	
	public String getPassword() { return password; }
	
	public String createPassword(String url, String input, int len, int mod) 
	throws NoSuchAlgorithmException {
		String buffer = url+input;
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		md5.update(buffer.getBytes());
		byte[] iv = md5.digest();
		
		buffer += new String(iv);
		md5.update(buffer.getBytes());
		byte[] k = md5.digest();
		
		int[] key = new int[MAXLEN];
		ZUC zuc = new ZUC();
		zuc.Initialization(k, iv);
		zuc.generateKeystream(key, key.length);
		
		int cnt = 0;
		char[] pwd = new char[len];
		for (int i = len; i < MAXLEN && cnt < len; i++) {
			for (int j = 0; j <4 && cnt < len; j++) {
				int type = 0;
				char tmp = (char)(key[i]&0x7f);
				
				//System.out.println(cnt+ "\t" + Integer.toHexString(tmp&0xff));
				
				if (tmp == 0) tmp = '*';
				if (Character.isUpperCase(tmp)) type = SET_UPPER;
				else if (Character.isLowerCase(tmp)) type = SET_LOWER;
				else if (Character.isDigit(tmp)) type = SET_NUMBER;
				else type = SET_SPECIAL; 
				
				if ((type & mod) > 0) {
					if (type == SET_SPECIAL && 
							(tmp < 33 || tmp >= 127)) {
						tmp = (char)(tmp%94+33);
						while (Character.isDigit(tmp) || Character.isLetter(tmp)) {
							tmp = (char)(tmp%94+33);
						}
					} else {
						pwd[cnt++] = tmp;
					}
				} else if (type == SET_LOWER && (mod&SET_UPPER) > 0) {
					pwd[cnt++] = Character.toUpperCase(tmp);
				} else if (type == SET_UPPER && (mod&SET_LOWER) > 0) {
					pwd[cnt++] = Character.toLowerCase(tmp);
				} else if ((mod & SET_NUMBER)>0){
					pwd[cnt++] = (char)('0'+tmp%10);
				} else if ((mod & SET_SPECIAL) > 0) {
					tmp = (char)(tmp%94+33);
					while (Character.isDigit(tmp) || Character.isLetter(tmp)) {
						tmp = (char)(tmp%94+33);
					}
				}
				
				key[i] >>>= 8;
			}	
		}
		password = new String(pwd);
		return password;
	}
}


